[AWS Glue]ジョブ失敗時の通知設定をCloudFormationで実装してみた
こんにちは、CX事業本部の若槻です。
AWSのETLサービスであるAWS Glueのジョブ失敗時の通知はCloudWatch Eventsを使用することにより実装が可能です。以下の記事ではコンソールを用いた設定方法が紹介されています。
今回は、上記で紹介されているAWS Glueのジョブ失敗時の通知設定をCloudFormationで実装してみました。
作ってみた
CloudFormationテンプレート
Glueジョブ含めたリソース定義を行っています。
% touch template.yaml
AWSTemplateFormatVersion: '2010-09-09' Resources: RawDataBucket: Type: AWS::S3::Bucket DeletionPolicy: Retain Properties: BucketName: !Sub raw-data-${AWS::AccountId}-${AWS::Region} GlueJobExecuteRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - glue.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: etl-glue-job-policy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - glue:* - cloudwatch:PutMetricData - s3:ListAllMyBuckets - s3:ListBucket - s3:GetBucketAcl - s3:GetBucketLocation Resource: "*" - Effect: Allow Action: - logs:CreateLogStream - logs:CreateLogGroup - logs:PutLogEvents Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws-glue/jobs/* - Effect: Allow Action: - s3:PutObject - s3:GetObject - s3:DeleteObject Resource: - !Sub arn:aws:s3:::${RawDataBucket}/*/* - !Sub arn:aws:s3:::${GlueJobTempDirBucket}/admin/* - !Sub arn:aws:s3:::${GlueJobScriptBucket}/admin/* GlueJobTempDirBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub glue-job-temporary-${AWS::AccountId}-${AWS::Region} GlueJobScriptBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub glue-job-script-${AWS::AccountId}-${AWS::Region} SJIStoUTF8GlueJob: Type: AWS::Glue::Job Properties: Name: sjis-to-utf8-job Command: Name: pythonshell PythonVersion: 3 ScriptLocation: !Sub s3://${GlueJobScriptBucket}/admin/sjis-to-utf8.py DefaultArguments: --TempDir: !Sub s3://${GlueJobTempDirBucket}/admin --BUCKET_NAME: !Sub ${RawDataBucket} --SRC_OBJECT_KEY: sjis-data/raw-sjis-data.csv --SRC_FILE_ENCODING: shift_jis --DEST_OBJECT_PREFIX: utf8-data ExecutionProperty: MaxConcurrentRuns: 1 MaxRetries: 0 Role: !Ref GlueJobExecuteRole GlueJobFailureNotificationTopic: Type: AWS::SNS::Topic Properties: TopicName: job-failure-notification-topic SJIStoUTF8JobFailureEventRule: Type: AWS::Events::Rule Properties: EventPattern: source: - aws.glue detail-type: - Glue Job State Change detail: state: - FAILED jobName: - !Ref SJIStoUTF8GlueJob State: ENABLED Targets: - Arn: !Ref GlueJobFailureNotificationTopic Id: !GetAtt GlueJobFailureNotificationTopic.TopicName GlueJobFailureEventTopicPolicy: Type: AWS::SNS::TopicPolicy Properties: Topics: - !Ref GlueJobFailureNotificationTopic PolicyDocument: Statement: - Effect: Allow Principal: Service: events.amazonaws.com Action: sns:Publish Resource: !Ref GlueJobFailureNotificationTopic
Glueジョブスクリプト
スクリプトは、試しにエラーを起こせれば何でも良いですが、今回は以下記事のスクリプトを流用します。
% touch sjis-to-utf8.py
import boto3 import sys import uuid from awsglue.utils import getResolvedOptions # ジョブパラメータの読み込み args = getResolvedOptions(sys.argv, ['BUCKET_NAME', 'SRC_OBJECT_KEY', 'SRC_FILE_ENCODING', 'DEST_OBJECT_PREFIX']) # S3 Service Resource 準備 s3 = boto3.resource('s3') # ファイルを文字コード変換してロード src_obj = s3.Object(args['BUCKET_NAME'], args['SRC_OBJECT_KEY']) body = src_obj.get()['Body'].read().decode(args['SRC_FILE_ENCODING']) # ファイルを保存 dest_obj_file_name = str(uuid.uuid4()) dest_obj = s3.Object(args['BUCKET_NAME'], args['DEST_OBJECT_PREFIX'] + '/' + dest_obj_file_name) dest_obj.put(Body = body) # ファイルを削除 src_obj.delete()
このスクリプトはS3バケットに特定のキーのファイルが存在しなければエラーとなります。
デプロイ
CloudFormationスタックをデプロイします。
% aws cloudformation deploy \ --template-file template.yaml \ --stack-name Glue-Job-Failure-Notify-Stack \ --capabilities CAPABILITY_NAMED_IAM \ --no-fail-on-empty-changeset
GlueジョブのスクリプトをS3バケットにアップロードします。
% ACCOUNT_ID=<Account ID> % AWS_REGION=<AWS Region> % aws s3 cp sjis-to-utf8.py s3://glue-job-script-${ACCOUNT_ID}-${AWS_REGION}/admin/sjis-to-utf8.py
サブスクリプション登録
SNSトピックのサブスクリプションに通知先のメールアドレスを登録します。
% to_address=<Mail Address> % aws sns subscribe \ --topic-arn arn:aws:sns:${AWS_REGION}:${ACCOUNT_ID}:job-failure-notification-topic \ --protocol email \ --notification-endpoint ${to_address}
上記コマンドを実行すると下記のような登録確認メールが届くので、Confirm subscription
をクリックして登録を完了させます。
動作確認
通知を発生させてみる
ジョブを実行します。
% aws glue start-job-run --job-name sjis-to-utf8-job
すると下記のようなメールが届きます。
開始 AWS Notifications <no-reply@sns.amazonaws.com> 宛先: <xxxxxxxxxxxxxxxxxx> 件名 AWS Notification Message {"version":"0","id":"e240736b-0903-610f-1ce8-e6f1eeef7b7d","detail-type":"Glue Job State Change","source":"aws.glue","account":"0123456789","time":"2020-12-28T13:16:53Z","region":"ap-northeast-1","resources":[],"detail":{"jobName":"sjis-to-utf8-job","severity":"ERROR","state":"FAILED","jobRunId":"jr_f41dd4aeed489bff491de6cc8f1d9b73383b601d174e180a87450ceb4f5664a8","message":"NoSuchKey: An error occurred (NoSuchKey) when calling the GetObject operation: The specified key does not exist."}}
detail - jobNameよりエラー通知がsjis-to-utf8-job
ジョブで発生したことが分かります。またdetail - messageにNoSuchKey: An error occurred (NoSuchKey) when calling the GetObject operation: The specified key does not exist.
とあるため、S3バケットからオブジェクト取得時に指定のキーが存在しなかったためエラーとなっていることが分かります。
ジョブ失敗のメトリクスの確認
CloudWatchのマネジメントコンソールで該当のルールを開き、[ルールのメトリクスを表示]をクリックします。
メトリクス名TriggeredRules
にチェックを入れると、グラフにジョブ失敗のメトリクスが記録されていることが確認できます。
おわりに
AWS Glueのジョブ失敗時の通知設定をCloudFormationで実装してみました。
Glueジョブを使用する際は是非ともセットで実装したいですね。
参考
以上